/*
 * FaceCat图形通讯框架
 * 著作权编号:2015SR229355+2020SR0266727
 * 上海卷卷猫信息技术有限公司
 */

using System;
using System.Collections.Generic;

namespace FaceCat
{
    /// <summary>
    /// 字符行
    /// </summary>
    public struct FCWordLine
    {
        /// <summary>
        /// 创建行
        /// </summary>
        /// <param name="start">开始索引</param>
        /// <param name="end">结束索引</param>
        public FCWordLine(int start, int end)
        {
            m_start = start;
            m_end = end;
            m_line = 0;
        }

        /// <summary>
        /// 结束索引
        /// </summary>
        public int m_end;

        /// <summary>
        /// 行号
        /// </summary>
        public int m_line;

        /// <summary>
        /// 开始索引
        /// </summary>
        public int m_start;
    }

    /// <summary>
    /// 撤销重复信息
    /// </summary>
    public class FCRedoUndoInfo
    {
        /// <summary>
        /// 创建信息
        /// </summary>
        public FCRedoUndoInfo(String text, int selectionStart, int selectionLength)
        {
            m_text = text;
            m_selectionStart = selectionStart;
            m_selectionLength = selectionLength;
        }

        /// <summary>
        /// 选中开始位置
        /// </summary>
        public int m_selectionStart = -1;

        /// <summary>
        /// 选中长度
        /// </summary>
        public int m_selectionLength = 0;

        /// <summary>
        /// 文字
        /// </summary>
        public String m_text = "";
    }

    /// <summary>
    /// 文本框视图
    /// </summary>
    public class FCTextBox : FCDiv
    {
        /// <summary>
        /// 创建视图
        /// </summary>
        public FCTextBox()
        {
            this.setCursor(FCCursors.IBeam);
            m_size = new FCSize(100, 20);
            setTabStop(true);
        }

        public int m_changeID = FCNative.getChangeID();

        /// <summary>
        /// 是否正在复制
        /// </summary>
        public bool m_isCopy;

        /// <summary>
        /// 键盘是否按下
        /// </summary>
        public bool m_isKeyDown;

        /// <summary>
        /// 是否触摸按下
        /// </summary>
        public bool m_isTouchDown;

        /// <summary>
        /// 横向偏移量
        /// </summary>
        public int m_offsetX = 0;

        /// <summary>
        /// 文字矩形范围
        /// </summary>
        public ArrayList<FCRectF> m_ranges = new ArrayList<FCRectF>();

        /// <summary>
        /// 重做栈
        /// </summary>
        public Stack<FCRedoUndoInfo> m_redoStack = new Stack<FCRedoUndoInfo>();

        /// <summary>
        /// 是否显示光标
        /// </summary>
        public bool m_showCursor = false;

        /// <summary>
        /// 开始移动的坐标
        /// </summary>
        public int m_startMovingIndex = -1;

        /// <summary>
        /// 结束移动的坐标
        /// </summary>
        public int m_stopMovingIndex = -1;

        /// <summary>
        /// 文字是否改变
        /// </summary>
        public bool m_textChanged = false;

        /// <summary>
        /// 光标闪烁频率
        /// </summary>
        public int TICK = 500;

        /// <summary>
        /// 秒表ID
        /// </summary>
        private int m_timerID = getNewTimerID();

        /// <summary>
        /// 撤销栈
        /// </summary>
        public Stack<FCRedoUndoInfo> m_undoStack = new Stack<FCRedoUndoInfo>();

        /// <summary>
        /// 文字大小
        /// </summary>
        public ArrayList<FCSizeF> m_wordsSize = new ArrayList<FCSizeF>();

        public FCPoint m_cursorPoint = new FCPoint();

        /// <summary>
        /// 获取光标位置
        /// </summary>
        public virtual FCPoint getCursorPoint()
        {
            return m_cursorPoint;
        }

        /// <summary>
        /// 设置光标位置
        /// </summary>
        public virtual void setCursorPoint(FCPoint value)
        {
            m_cursorPoint = value;
        }

        /// <summary>
        /// 获取行数
        /// </summary>
        public virtual int getLinesCount()
        {
            return m_lines.size();
        }

        public int m_lineHeight = 20;

        /// <summary>
        /// 获取行高
        /// </summary>
        public virtual int getLineHeight()
        {
            return m_lineHeight;
        }

        /// <summary>
        /// 设置行高
        /// </summary>
        public virtual void setLineHeight(int value)
        {
            m_lineHeight = value;
        }

        public ArrayList<FCWordLine> m_lines = new ArrayList<FCWordLine>();

        /// <summary>
        /// 获取所有行
        /// </summary>
        public virtual ArrayList<FCWordLine> getLines()
        {
            return m_lines;
        }

        public bool m_multiline = false;

        /// <summary>
        /// 获取是否多行显示
        /// </summary>
        public virtual bool isMultiline()
        {
            return m_multiline;
        }

        /// <summary>
        /// 设置是否多行显示
        /// </summary>
        public virtual void setMultiline(bool value)
        {
            if (m_multiline != value)
            {
                m_multiline = value;
                m_textChanged = true;
            }
            setShowVScrollBar(m_multiline);
        }

        public char m_passwordChar;

        /// <summary>
        /// 获取密码字符
        /// </summary>
        public virtual char getPasswordChar()
        {
            return m_passwordChar;
        }

        /// <summary>
        /// 设置密码字符
        /// </summary>
        public virtual void setPasswordChar(char value)
        {
            m_passwordChar = value;
            m_textChanged = true;
        }

        public bool m_readOnly = false;

        /// <summary>
        /// 获取是否只读
        /// </summary>
        public virtual bool isReadOnly()
        {
            return m_readOnly;
        }

        /// <summary>
        /// 设置是否只读
        /// </summary>
        public virtual void setReadOnly(bool value)
        {
            m_readOnly = value;
        }

        public bool m_rightToLeft;

        /// <summary>
        /// 获取是否从右向左绘制
        /// </summary>
        public virtual bool rightToLeft()
        {
            return m_rightToLeft;
        }

        /// <summary>
        /// 设置是否从右向左绘制
        /// </summary>
        public virtual void setRightToLeft(bool value)
        {
            m_rightToLeft = value;
            m_textChanged = true;
        }

        /// <summary>
        /// 获取选中的文字
        /// </summary>
        public virtual String getSelectionText()
        {
            String text = getText();
            if (text == null)
            {
                text = "";
            }
            int textLength = text.Length;
            if (textLength > 0 && m_selectionStart != textLength && m_selectionStart != -1)
            {
                String selectedText = text.Substring(m_selectionStart, m_selectionLength);
                return selectedText;
            }
            return String.Empty;
        }

        public long m_selectionBackColor = FCColor.rgb(10, 36, 106);

        /// <summary>
        /// 获取选中的背景色
        /// </summary>
        public virtual long getSelectionBackColor()
        {
            return m_selectionBackColor;
        }

        /// <summary>
        /// 设置选中的背景色
        /// </summary>
        public virtual void setSelectionBackColor(long value)
        {
            m_selectionBackColor = value;
        }

        public long m_selectionTextColor = FCColor.rgb(255, 255, 255);

        /// <summary>
        /// 获取选中的文字色
        /// </summary>
        public long getSelectionTextColor()
        {
            return m_selectionTextColor;
        }

        /// <summary>
        /// 设置选中的文字色
        /// </summary>
        public virtual void setSelectionTextColor(long value)
        {
            m_selectionTextColor = value;
        }

        public int m_selectionLength;

        /// <summary>
        /// 获取选中长度
        /// </summary>
        public virtual int getSelectionLength()
        {
            return m_selectionLength;
        }

        /// <summary>
        /// 设置选中长度
        /// </summary>
        public virtual void setSelectionLength(int value)
        {
            m_selectionLength = value;
        }

        public int m_selectionStart = -1;

        /// <summary>
        /// 获取选中开始位置
        /// </summary>
        public virtual int getSelectionStart()
        {
            return m_selectionStart;
        }

        /// <summary>
        /// 设置选中开始位置
        /// </summary>
        public virtual void setSelectionStart(int value)
        {
            m_selectionStart = value;
            if (m_selectionStart > getText().Length)
            {
                m_selectionStart = getText().Length;
            }
        }

        public String m_tempText;

        /// <summary>
        /// 获取临时文字
        /// </summary>
        public virtual String getTempText()
        {
            return m_tempText;
        }

        /// <summary>
        /// 设置临时文字
        /// </summary>
        public virtual void setTempText(String tempText)
        {
            m_tempText = tempText;
        }

        public long m_tempTextColor = FCColor.DisabledText;

        /// <summary>
        /// 获取临时文字的颜色
        /// </summary>
        public virtual long getTempTextColor()
        {
            return m_tempTextColor;
        }

        /// <summary>
        /// 设置临时文字的颜色
        /// </summary>
        public virtual void setTempTextColor(long tempTextColor)
        {
            m_tempTextColor = tempTextColor;
        }

        public FCHorizontalAlign m_textAlign = FCHorizontalAlign.Left;

        /// <summary>
        /// 获取内容的横向排列样式
        /// </summary>
        public virtual FCHorizontalAlign getTextAlign()
        {
            return m_textAlign;
        }

        /// <summary>
        /// 设置内容的横向排列样式
        /// </summary>
        public virtual void setTextAlign(FCHorizontalAlign value)
        {
            m_textAlign = value;
        }

        public bool m_wordWrap = false;

        /// <summary>
        /// 获取多行编辑视图是否启动换行
        /// </summary>
        public virtual bool wordWrap()
        {
            return m_wordWrap;
        }

        /// <summary>
        /// 设置多行编辑视图是否启动换行
        /// </summary>
        public virtual void setWordWrap(bool value)
        {
            if (m_wordWrap != value)
            {
                m_wordWrap = value;
                m_textChanged = true;
            }
            setShowHScrollBar(!m_wordWrap);
        }

        /// <summary>
        /// 判断是否可以重复
        /// </summary>
        /// <returns>是否可以重复</returns>
        public virtual bool canRedo()
        {
            if (m_redoStack.Count > 0)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 判断是否可以撤销
        /// </summary>
        /// <returns>是否可以撤销</returns>
        public virtual bool canUndo()
        {
            if (m_undoStack.Count > 0)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 重置撤销重复
        /// </summary>
        public virtual void clearRedoUndo()
        {
            m_undoStack.Clear();
            m_redoStack.Clear();
        }

        /// <summary>
        /// 光标向下移动
        /// </summary>
        public virtual void cursorDown()
        {
            FCHost host = getNative().getHost();
            int rangeSize = m_ranges.size();
            int start = m_selectionStart + m_selectionLength < rangeSize - 1 ? m_selectionStart + m_selectionLength : rangeSize - 1;
            if (host.isKeyPress(0x10))
            {
                start = m_stopMovingIndex + 1;
            }
            else
            {
                if (m_selectionLength > 0)
                {
                    m_selectionLength = 1;
                }
            }
            int lineCount = m_lines.size();
            for (int i = 0; i < lineCount; i++)
            {
                FCWordLine line = m_lines[i];
                if (start >= line.m_start && start <= line.m_end)
                {
                    if (i != lineCount - 1)
                    {
                        FCWordLine newLine = m_lines[i + 1];
                        int findIndex = -1;
                        if (m_ranges[newLine.m_end].left <= m_ranges[start].left)
                        {
                            findIndex = newLine.m_end;
                        }
                        else
                        {
                            for (int j = newLine.m_end; j >= newLine.m_start; j--)
                            {
                                if (m_ranges[j].right < m_ranges[start].right)
                                {
                                    findIndex = j;
                                    break;
                                }
                            }
                            if (findIndex == -1)
                            {
                                findIndex = newLine.m_end;
                            }
                        }
                        if (host.isKeyPress(0x10))
                        {
                            setMovingIndex(m_startMovingIndex, findIndex);
                        }
                        else
                        {
                            m_selectionStart = findIndex;
                            m_selectionLength = 0;
                            m_startMovingIndex = m_selectionStart;
                            m_stopMovingIndex = m_selectionStart;
                        }
                        m_showCursor = true;
                        startTimer(m_timerID, TICK);
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// 光标移动到最右端
        /// </summary>
        public virtual void cursorEnd()
        {
            FCHost host = getNative().getHost();
            int rangeSize = m_ranges.size();
            int start = m_selectionStart + m_selectionLength < rangeSize - 1 ? m_selectionStart + m_selectionLength : rangeSize - 1;
            if (host.isKeyPress(0x10))
            {
                start = m_stopMovingIndex;
            }
            int lineCount = m_lines.size();
            for (int i = 0; i < lineCount; i++)
            {
                FCWordLine line = m_lines[i];
                for (int j = line.m_start; j <= line.m_end; j++)
                {
                    if (j == start)
                    {
                        if (j == line.m_start && i > 0)
                        {
                            line = m_lines[i - 1];
                        }
                        if (host.isKeyPress(0x10))
                        {
                            setMovingIndex(m_startMovingIndex, line.m_end + 1);
                        }
                        else
                        {
                            m_selectionStart = line.m_end + 1;
                            m_selectionLength = 0;
                            m_startMovingIndex = m_selectionStart;
                            m_stopMovingIndex = m_selectionStart;
                        }
                        m_showCursor = true;
                        startTimer(m_timerID, TICK);
                        return;
                    }
                }
            }
        }

        /// <summary>
        /// 光标移动到最左端
        /// </summary>
        public virtual void cursorHome()
        {
            FCHost host = getNative().getHost();
            int rangeSize = m_ranges.size();
            int start = m_selectionStart < rangeSize - 1 ? m_selectionStart : rangeSize - 1;
            if (host.isKeyPress(0x10))
            {
                start = m_stopMovingIndex;
            }
            int lineCount = m_lines.size();
            for (int i = 0; i < lineCount; i++)
            {
                FCWordLine line = m_lines[i];
                for (int j = line.m_start; j <= line.m_end; j++)
                {
                    if (j == start)
                    {
                        if (j == line.m_start && i > 0)
                        {
                            line = m_lines[i - 1];
                        }
                        if (host.isKeyPress(0x10))
                        {
                            setMovingIndex(m_startMovingIndex, line.m_start + 1);
                        }
                        else
                        {
                            m_selectionStart = line.m_start + 1;
                            m_selectionLength = 0;
                            m_startMovingIndex = m_selectionStart;
                            m_stopMovingIndex = m_selectionStart;
                        }
                        m_showCursor = true;
                        startTimer(m_timerID, TICK);
                        return;
                    }
                }
            }
        }

        /// <summary>
        /// 光标向左移动
        /// </summary>
        public virtual void cursorLeft()
        {
            FCHost host = getNative().getHost();
            if (host.isKeyPress(0x10))
            {
                setMovingIndex(m_startMovingIndex, m_stopMovingIndex - 1);
            }
            else
            {
                if (m_selectionStart > 0)
                {
                    m_selectionStart -= 1;

                    FCRectF sRange = m_ranges[m_selectionStart];
                    if (m_selectionStart > 0 && sRange.right - sRange.left == 0)
                    {
                        m_selectionStart -= 1;
                    }
                }
                m_selectionLength = 0;
                m_startMovingIndex = m_selectionStart;
                m_stopMovingIndex = m_selectionStart;
            }
        }

        /// <summary>
        /// 光标向右移动
        /// </summary>
        public virtual void cursorRight()
        {
            FCHost host = getNative().getHost();
            if (host.isKeyPress(0x10))
            {
                setMovingIndex(m_startMovingIndex, m_stopMovingIndex + 1);
            }
            else
            {
                int rangeSize = m_ranges.size();
                int start = m_selectionStart + m_selectionLength < rangeSize - 1 ? m_selectionStart + m_selectionLength : rangeSize - 1;
                if (start < rangeSize)
                {
                    m_selectionStart = start + 1;

                    if (m_selectionStart < m_ranges.size())
                    {
                        FCRectF sRange = m_ranges[m_selectionStart];
                        if (sRange.right - sRange.left == 0)
                        {
                            m_selectionStart++;
                        }
                    }
                }
                m_selectionLength = 0;
                m_startMovingIndex = m_selectionStart;
                m_stopMovingIndex = m_selectionStart;
            }
        }

        /// <summary>
        /// 光标向上移动
        /// </summary>
        public virtual void cursorUp()
        {
            FCHost host = getNative().getHost();
            int rangeSize = m_ranges.size();
            int start = m_selectionStart < rangeSize - 1 ? m_selectionStart : rangeSize - 1;
            if (host.isKeyPress(0x10))
            {
                start = m_stopMovingIndex;
            }
            else
            {
                if (m_selectionLength > 0)
                {
                    m_selectionLength = 1;
                }
            }
            int lineCount = m_lines.size();
            for (int i = 0; i < lineCount; i++)
            {
                FCWordLine line = m_lines[i];
                if (start >= line.m_start && start <= line.m_end)
                {
                    if (i != 0)
                    {
                        FCWordLine newLine = m_lines[i - 1];
                        int findIndex = -1;
                        if (m_ranges[newLine.m_end].left <= m_ranges[start].left)
                        {
                            findIndex = newLine.m_end;
                        }
                        else
                        {
                            for (int j = newLine.m_end; j >= newLine.m_start; j--)
                            {
                                if (m_ranges[j].right < m_ranges[start].right)
                                {
                                    findIndex = j;
                                    break;
                                }
                            }
                            if (findIndex == -1)
                            {
                                findIndex = newLine.m_end;
                            }
                        }
                        if (host.isKeyPress(0x10))
                        {
                            setMovingIndex(m_startMovingIndex, findIndex);
                        }
                        else
                        {
                            m_selectionStart = findIndex;
                            m_selectionLength = 0;
                            m_startMovingIndex = m_selectionStart;
                            m_stopMovingIndex = m_selectionStart;
                        }
                        m_showCursor = true;
                        startTimer(m_timerID, TICK);
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// 删除字符
        /// </summary>
        public virtual void deleteWord()
        {
            String text = getText();
            if (text == null)
            {
                text = "";
            }
            int textLength = text.Length;
            if (textLength > 0)
            {
                int oldLines = m_lines.size();
                String left = "", right = "";
                int rightIndex = -1;
                if (m_selectionLength > 0)
                {
                    left = m_selectionStart > 0 ? text.Substring(0, m_selectionStart) : "";
                    rightIndex = m_selectionStart + m_selectionLength;
                }
                else
                {
                    left = m_selectionStart > 0 ? text.Substring(0, m_selectionStart - 1) : "";
                    rightIndex = m_selectionStart + m_selectionLength;
                }
                if (rightIndex < textLength)
                {
                    right = text.Substring(rightIndex);
                }
                if (left.Length > 1)
                {
                    if (left[left.Length - 1] == '\r')
                    {
                        left = left.Substring(0, left.Length - 1);
                    }
                }
                if (right.Length > 1)
                {
                    if (right[0] == '\n')
                    {
                        right = right.Substring(1);
                    }
                }
                String newText = left + right;
                m_text = newText;
                textLength = newText.Length;
                m_selectionStart = left.Length;
                if (textLength == 0)
                {
                    m_selectionStart = 0;
                }
                else
                {
                    if (m_selectionStart > textLength)
                    {
                        m_selectionStart = textLength;
                    }
                }
                m_selectionLength = 0;
            }
        }

        /// <summary>
        /// 销毁方法
        /// </summary>
        public override void delete()
        {
            if (!isDeleted())
            {
                stopTimer(m_timerID);
                m_lines.clear();
                m_ranges.clear();
                m_redoStack.Clear();
                m_undoStack.Clear();
                m_wordsSize.clear();
            }
            base.delete();
        }

        /// <summary>
        /// 获取内容的高度
        /// </summary>
        /// <returns>高度</returns>
        public override int getContentHeight()
        {
            int hmax = base.getContentHeight();
            int cheight = 0;
            int rangeSize = m_ranges.size();
            for (int i = 0; i < rangeSize; i++)
            {
                if (cheight < m_ranges[i].bottom)
                {
                    cheight = (int)m_ranges[i].bottom;
                }
            }
            return hmax > cheight ? hmax : cheight;
        }

        /// <summary>
        /// 获取内容的宽度
        /// </summary>
        /// <returns>宽度</returns>
        public override int getContentWidth()
        {
            int wmax = base.getContentWidth();
            int cwidth = 0;
            int rangeSize = m_ranges.size();
            for (int i = 0; i < rangeSize; i++)
            {
                if (cwidth < m_ranges[i].right)
                {
                    cwidth = (int)m_ranges[i].right;
                }
            }
            return wmax > cwidth ? wmax : cwidth;
        }

        /// <summary>
        /// 获取视图类型
        /// </summary>
        /// <returns>视图类型</returns>
        public override String getViewType()
        {
            return "TextBox";
        }

        /// <summary>
        /// 获取属性值
        /// </summary>
        /// <param name="name">属性名称</param>
        /// <param name="value">返回属性值</param>
        /// <param name="type">返回属性类型</param>
        public override void getAttribute(String name, ref String value, ref String type)
        {
            switch (name)
            {
                case "lineheight":
                    type = "int";
                    value = FCTran.intToStr(getLineHeight());
                    break;
                case "multiline":
                    type = "bool";
                    value = FCTran.boolToStr(isMultiline());
                    break;
                case "passwordchar":
                    type = "text";
                    value = getPasswordChar().ToString();
                    break;
                case "readonly":
                    type = "bool";
                    value = FCTran.boolToStr(isReadOnly());
                    break;
                case "righttoleft":
                    type = "bool";
                    value = FCTran.boolToStr(rightToLeft());
                    break;
                case "selectionbackcolor":
                    type = "color";
                    value = FCTran.colorToStr(getSelectionBackColor());
                    break;
                case "selectiontextcolor":
                    type = "color";
                    value = FCTran.colorToStr(getSelectionTextColor());
                    break;
                case "temptext":
                    type = "text";
                    value = getTempText();
                    break;
                case "temptextcolor":
                    type = "color";
                    value = FCTran.colorToStr(getTempTextColor());
                    break;
                case "textalign":
                    type = "enum:FCHorizontalAlign";
                    value = FCTran.horizontalAlignToStr(getTextAlign());
                    break;
                case "wordwrap":
                    type = "bool";
                    value = FCTran.boolToStr(wordWrap());
                    break;
                default:
                    base.getAttribute(name, ref value, ref type);
                    break;
            }
        }

        /// <summary>
        /// 获取属性名称列表
        /// </summary>
        /// <returns>属性名称列表</returns>
        public override ArrayList<String> getAttributeNames()
        {
            ArrayList<String> attributeNames = base.getAttributeNames();
            attributeNames.AddRange(new String[] { "LineHeight", "Multiline", "PasswordChar", "ReadOnly", "RightToLeft", "SelectionBackColor", "SelectionTextColor", "TempText", "TempTextColor", "TextAlign", "WordWrap" });
            return attributeNames;
        }

        /// <summary>
        /// 判断字符索引所在行是否可见
        /// </summary>
        /// <param name="index">字符索引</param>
        /// <param name="visiblePercent">可见百分比</param>
        /// <returns>是否可见</returns>
        public virtual bool isLineVisible(int index, double visiblePercent)
        {
            int rangeSize = m_ranges.size();
            if (rangeSize > 0)
            {
                if (index >= 0 && index < rangeSize)
                {
                    int top = 0, scrollV = 0, sch = 0;
                    FCHScrollBar hScrollBar = getHScrollBar();
                    FCVScrollBar vScrollBar = getVScrollBar();
                    if (hScrollBar != null && hScrollBar.isVisible())
                    {
                        sch = hScrollBar.getHeight();
                    }
                    if (vScrollBar != null && vScrollBar.isVisible())
                    {
                        scrollV = -vScrollBar.getPos();
                    }
                    top = scrollV;
                    int cell = 1;
                    int floor = getHeight() - cell - sch - 1;
                    FCRectF indexRect = m_ranges[index];
                    int indexTop = (int)indexRect.top + scrollV;
                    int indexBottom = (int)indexRect.bottom + scrollV;
                    return lineVisible(indexTop, indexBottom, cell, floor, m_lineHeight, visiblePercent);
                }
            }
            return false;
        }


        /// <summary>
        /// 插入字符
        /// </summary>
        /// <param name="str">字符串</param>
        public virtual void insertWord(String str)
        {
            String text = getText();
            if (text == null)
            {
                text = "";
            }
            if (text.Length == 0 || m_selectionStart == text.Length)
            {
                text = text + str;
                m_text = text;
                m_selectionStart = text.Length;
            }
            else
            {
                int sIndex = m_selectionStart > text.Length ? text.Length : m_selectionStart;
                String left = sIndex > 0 ? text.Substring(0, sIndex) : "";
                String right = "";
                int rightIndex = m_selectionStart + (m_selectionLength == 0 ? 0 : m_selectionLength);
                if (rightIndex < text.Length)
                {
                    right = text.Substring(rightIndex);
                }
                if (left.Length > 1 && right.Length > 1 && left[left.Length - 1] == '\r' && (text[left.Length] == '\n' || right[0] == '\n'))
                {
                    if (right[0] == '\n')
                    {
                        text = left.Substring(0, left.Length - 1) + str + "\r\n" + right.Substring(1);
                    }
                    else
                    {
                        text = left.Substring(0, left.Length - 1) + str + "\r\n" + right;
                    }
                }
                else
                {
                    text = left + str + right;
                }
                m_text = text;
                m_selectionStart += str.Length;
                if (m_selectionStart > text.Length)
                {
                    m_selectionStart = text.Length;
                }
                m_selectionLength = 0;
            }
        }

        /// <summary>
        /// 判断行是否可见
        /// </summary>
        public virtual bool lineVisible(int indexTop, int indexBottom, int cell, int floor, int lineHeight, double visiblePercent)
        {
            if (indexTop < cell)
            {
                indexTop = cell;
            }
            else if (indexTop > floor)
            {
                indexTop = floor;
            }
            if (indexBottom < cell)
            {
                indexBottom = cell;
            }
            else if (indexBottom > floor)
            {
                indexBottom = floor;
            }
            if (indexBottom - indexTop >= (int)(lineHeight * visiblePercent))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 文本输入方法
        /// </summary>
        /// <param name="ch">文字</param>
        public override void onChar(char ch)
        {
            if (!m_readOnly)
            {
                base.onChar(ch);
                FCHost host = getNative().getHost();
                if (!host.isKeyPress(0x11))
                {
                    int oldLines = m_lines.size();
                    if (ch != 8)
                    {
                        if (m_multiline)
                        {
                            FCRedoUndoInfo newReoUndoInfo = new FCRedoUndoInfo(getText(), getSelectionStart(), getSelectionLength());
                            String iWord = ch.ToString();
                            if (ch == 13)
                            {
                                iWord = iWord + "\n";
                            }
                            insertWord(iWord);
                            onTextChanged();
                            if (m_textChanged)
                            {
                                m_undoStack.Push(newReoUndoInfo);
                            }
                        }
                        else
                        {
                            if (ch != 13)
                            {
                                FCRedoUndoInfo newReoUndoInfo = new FCRedoUndoInfo(getText(), getSelectionStart(), getSelectionLength());
                                String iWord = ch.ToString();
                                insertWord(iWord);
                                onTextChanged();
                                if (m_textChanged)
                                {
                                    m_undoStack.Push(newReoUndoInfo);
                                }
                            }
                        }
                    }
                    invalidate();
                    if (!isLineVisible(m_selectionStart, 1.0f))
                    {
                        int newLines = m_lines.size();
                        if (newLines != oldLines)
                        {
                            FCVScrollBar vScrollBar = getVScrollBar();
                            if (vScrollBar != null)
                            {
                                vScrollBar.setPos(vScrollBar.getPos() + m_lineHeight * (newLines - oldLines));
                                invalidate();
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 复制文字
        /// </summary>
        public override void onCopy()
        {
            String selectionText = getSelectionText();
            if (selectionText != null && selectionText.Length > 0)
            {
                FCHost host = getNative().getHost();
                host.copy(selectionText);
                m_isCopy = true;
                base.onCopy();
            }
        }

        /// <summary>
        /// 剪切
        /// </summary>
        public override void onCut()
        {
            if (!m_readOnly)
            {
                onCopy();
                int oldLines = m_lines.size();
                FCRedoUndoInfo newReoUndoInfo = new FCRedoUndoInfo(getText(), getSelectionStart(), getSelectionLength());
                deleteWord();
                onTextChanged();
                if (m_textChanged)
                {
                    m_undoStack.Push(newReoUndoInfo);
                }
                invalidate();
                if (!isLineVisible(m_selectionStart, 1.0f))
                {
                    int newLines = m_lines.size();
                    if (newLines != oldLines)
                    {
                        FCVScrollBar vScrollBar = getVScrollBar();
                        if (vScrollBar != null)
                        {
                            vScrollBar.setPos(vScrollBar.getPos() + m_lineHeight * (newLines - oldLines));
                            invalidate();
                        }
                    }
                }
                base.onCut();
            }
        }

        /// <summary>
        /// 获取焦点方法
        /// </summary>
        public override void onGotFocus()
        {
            base.onGotFocus();
            m_showCursor = true;
            invalidate();
            startTimer(m_timerID, TICK);
        }

        /// <summary>
        /// 键盘方法
        /// </summary>
        /// <param name="key">按键</param>
        public override void onKeyDown(char key)
        {
            m_isKeyDown = true;
            FCHost host = getNative().getHost();
            if (host.isKeyPress(0x11))
            {
                base.onKeyDown(key);
                //全选
                if (key == 65)
                {
                    selectAll();
                }
                //重做
                else if (key == 89)
                {
                    redo();
                }
                //撤销
                else if (key == 90)
                {
                    undo();
                }
            }
            else
            {
                if (key >= 35 && key <= 40)
                {
                    if (key == 38 || key == 40)
                    {
                        callKeyEvents("onkeydown", key);
                        if (m_lines.size() > 1)
                        {
                            int offset = 0;
                            //光标向上移动
                            if (key == 38)
                            {
                                cursorUp();
                                if (!isLineVisible(m_stopMovingIndex, 0.9))
                                {
                                    offset = -m_lineHeight;
                                }
                            }
                            //光标向下移动
                            else if (key == 40)
                            {
                                cursorDown();
                                if (!isLineVisible(m_stopMovingIndex, 0.9))
                                {
                                    offset = m_lineHeight;
                                }
                            }
                            FCVScrollBar vScrollBar = getVScrollBar();
                            if (vScrollBar != null && vScrollBar.isVisible())
                            {
                                vScrollBar.setPos(vScrollBar.getPos() + offset);
                                vScrollBar.update();
                            }
                        }
                    }
                    else
                    {
                        base.onKeyDown(key);
                        //光标移动到最右端
                        if (key == 35)
                        {
                            cursorEnd();
                        }
                        //光标移动到最左端
                        else if (key == 36)
                        {
                            cursorHome();
                        }
                        //光标向左移动
                        else if (key == 37)
                        {
                            cursorLeft();
                        }
                        //光标向右移动
                        else if (key == 39)
                        {
                            cursorRight();
                        }
                    }
                }
                else
                {
                    base.onKeyDown(key);
                    //取消焦点
                    if (key == 27)
                    {
                        setFocused(false);
                    }
                    //删除
                    else if (key == 8 || key == 46)
                    {
                        if (!m_readOnly)
                        {
                            int oldLines = m_lines.size();
                            FCRedoUndoInfo newReoUndoInfo = new FCRedoUndoInfo(getText(), getSelectionStart(), getSelectionLength());
                            deleteWord();
                            onTextChanged();
                            if (m_textChanged)
                            {
                                m_undoStack.Push(newReoUndoInfo);
                            }
                            invalidate();
                            if (!isLineVisible(m_selectionStart, 1.0f))
                            {
                                int newLines = m_lines.size();
                                if (newLines != oldLines)
                                {
                                    FCVScrollBar vScrollBar = getVScrollBar();
                                    if (vScrollBar != null)
                                    {
                                        vScrollBar.setPos(vScrollBar.getPos() + m_lineHeight * (newLines - oldLines));
                                        invalidate();
                                    }
                                }
                            }
                        }
                    }
                }
            }
            invalidate();
        }

        /// <summary>
        /// 键盘抬起方法
        /// </summary>
        /// <param name="key">按键</param>
        public override void onKeyUp(char key)
        {
            base.onKeyUp(key);
            FCHost host = getNative().getHost();
            if (!host.isKeyPress(0x10) && !m_isTouchDown)
            {
                m_startMovingIndex = m_selectionStart;
                m_stopMovingIndex = m_selectionStart;
            }
            m_isKeyDown = false;
        }

        /// <summary>
        /// 丢失焦点方法
        /// </summary>
        public override void onLostFocus()
        {
            base.onLostFocus();
            stopTimer(m_timerID);
            m_isKeyDown = false;
            m_showCursor = false;
            invalidate();
        }

        /// <summary>
        /// 触摸按下方法
        /// </summary>
        /// <param name="touchInfo">触摸信息</param>
        public override void onTouchDown(FCTouchInfo touchInfo)
        {
            base.onTouchDown(touchInfo);
            if (touchInfo.m_firstTouch)
            {
                FCPoint mp = touchInfo.m_firstPoint;
                //单击
                if (touchInfo.m_clicks == 1)
                {
                    int sIndex = -1;
                    int linesCount = m_lines.size();
                    int oldLength = m_selectionLength;
                    m_selectionLength = 0;
                    m_startMovingIndex = -1;
                    m_stopMovingIndex = -1;
                    if (linesCount > 0)
                    {
                        FCHScrollBar hScrollBar = getHScrollBar();
                        FCVScrollBar vScrollBar = getVScrollBar();
                        int scrollH = (hScrollBar != null && hScrollBar.isVisible()) ? hScrollBar.getPos() : 0;
                        int scrollV = (vScrollBar != null && vScrollBar.isVisible()) ? vScrollBar.getPos() : 0;
                        scrollH += m_offsetX;
                        int x = mp.x + scrollH, y = mp.y + scrollV;
                        FCRectF lastRange = new FCRectF();
                        int rangeSize = m_ranges.size();
                        if (rangeSize > 0)
                        {
                            lastRange = m_ranges[rangeSize - 1];
                        }
                        for (int i = 0; i < linesCount; i++)
                        {
                            FCWordLine line = m_lines[i];
                            for (int j = line.m_start; j <= line.m_end; j++)
                            {
                                FCRectF rect = m_ranges[j];
                                if (i == linesCount - 1)
                                {
                                    rect.bottom += 3;
                                }
                                if (y >= rect.top && y <= rect.bottom)
                                {
                                    float sub = (rect.right - rect.left) / 2;
                                    if (sub > 0)
                                    {
                                        float nLeft = rect.left;
                                        if ((j == 0 && x <= nLeft + sub) || (x >= nLeft && x <= nLeft + sub))
                                        {
                                            sIndex = j;
                                            break;
                                        }
                                        else if (x >= nLeft + sub && x <= rect.right)
                                        {
                                            sIndex = j + 1;
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        sIndex = j;
                                        break;
                                    }
                                }
                            }
                            if (sIndex != -1)
                            {
                                break;
                            }
                        }
                        if (sIndex == -1)
                        {
                            if ((y >= lastRange.top && y <= lastRange.bottom && x > lastRange.right) || (y >= lastRange.bottom))
                            {
                                sIndex = rangeSize;
                            }
                        }
                    }
                    FCHost host = getNative().getHost();
                    if (host.isKeyPress(0x10))
                    {
                        if (sIndex != -1)
                        {
                            if (sIndex < m_selectionStart)
                            {
                                m_selectionLength = oldLength + Math.Abs(sIndex - m_selectionStart);
                                m_selectionStart = sIndex;
                            }
                            else
                            {
                                m_selectionLength = Math.Abs(sIndex - m_selectionStart);
                            }
                        }
                    }
                    else
                    {
                        if (sIndex != -1)
                        {
                            m_selectionStart = sIndex;
                        }
                        else
                        {
                            m_selectionStart = 0;
                        }
                    }
                    m_startMovingIndex = m_selectionStart;
                    m_stopMovingIndex = m_selectionStart;
                }
                //双击
                else if (touchInfo.m_clicks == 2)
                {
                    if (!m_multiline)
                    {
                        selectAll();
                    }
                }
            }
            m_isTouchDown = true;
            m_showCursor = true;
            startTimer(m_timerID, TICK);
            invalidate();
        }

        /// <summary>
        /// 触摸移动方法
        /// </summary>
        /// <param name="touchInfo">触摸信息</param>
        public override void onTouchMove(FCTouchInfo touchInfo)
        {
            base.onTouchMove(touchInfo);
            int width = getWidth(), height = getHeight();
            FCPoint mp = touchInfo.m_firstPoint;
            if (mp.x < 0)
            {
                mp.x = 0;
            }
            else if (mp.x > width)
            {
                mp.x = width;
            }
            if (mp.y < 0)
            {
                mp.y = 0;
            }
            else if (mp.y > height)
            {
                mp.y = height;
            }
            FCHost host = getNative().getHost();
            if (m_isTouchDown && !host.isKeyPress(0x10))
            {
                int linesCount = m_lines.size();
                if (linesCount > 0)
                {
                    int eIndex = -1;
                    FCHScrollBar hScrollBar = getHScrollBar();
                    FCVScrollBar vScrollBar = getVScrollBar();
                    FCPoint point = mp;
                    if (vScrollBar != null && vScrollBar.isVisible())
                    {
                        if (point.y <= 0)
                        {
                            vScrollBar.setPos(vScrollBar.getPos() - m_lineHeight);
                            update();
                        }
                        else if (point.y >= getHeight())
                        {
                            vScrollBar.setPos(vScrollBar.getPos() + m_lineHeight);
                            update();
                        }
                    }
                    int scrollH = (hScrollBar != null && hScrollBar.isVisible()) ? hScrollBar.getPos() : 0;
                    int scrollV = (vScrollBar != null && vScrollBar.isVisible()) ? vScrollBar.getPos() : 0;
                    scrollH += m_offsetX;
                    int x = point.x + scrollH, y = point.y + scrollV;
                    FCRectF lastRange = new FCRectF();
                    int rangeSize = m_ranges.size();
                    if (rangeSize > 0)
                    {
                        lastRange = m_ranges[rangeSize - 1];
                    }
                    for (int i = 0; i < linesCount; i++)
                    {
                        FCWordLine line = m_lines[i];
                        for (int j = line.m_start; j <= line.m_end; j++)
                        {
                            FCRectF rect = m_ranges[j];
                            if (i == linesCount - 1)
                            {
                                rect.bottom += 3;
                            }
                            if (eIndex == -1)
                            {
                                float tTop = rect.top;
                                if (i == 0)
                                {
                                    tTop = 0;
                                }
                                bool isFirst = false;
                                if (j == line.m_start)
                                {
                                    if (x < rect.left)
                                    {
                                        isFirst = true;
                                    }
                                }
                                if (y >= tTop && y <= rect.bottom)
                                {
                                    float sub = (rect.right - rect.left) / 2;
                                    if (j == line.m_end)
                                    {
                                        if (i == linesCount - 1)
                                        {
                                            eIndex = line.m_end + 1;
                                        }
                                        else
                                        {
                                            if (x > rect.right)
                                            {
                                                eIndex = line.m_end + 1;
                                            }
                                            else
                                            {
                                                eIndex = line.m_end;
                                            }
                                        }
                                        break;
                                    }
                                    else
                                    {
                                        if (isFirst)
                                        {
                                            eIndex = j;
                                            break;
                                        }
                                        else
                                        {
                                            if (sub > 0)
                                            {
                                                float nLeft = rect.left;
                                                if ((j == 0 && x <= nLeft + sub) || (x >= nLeft && x <= nLeft + sub))
                                                {
                                                    eIndex = j;
                                                    break;
                                                }
                                                else if (x >= nLeft + sub && x <= rect.right)
                                                {
                                                    eIndex = j + 1;
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        if (eIndex != -1)
                        {
                            break;
                        }
                    }
                    if (eIndex != -1)
                    {
                        m_stopMovingIndex = eIndex;
                    }
                    if (m_startMovingIndex == m_stopMovingIndex)
                    {
                        m_selectionStart = m_startMovingIndex;
                        m_selectionLength = 0;
                    }
                    else
                    {
                        m_selectionStart = m_startMovingIndex < m_stopMovingIndex ? m_startMovingIndex : m_stopMovingIndex;
                        m_selectionLength = Math.Abs(m_startMovingIndex - m_stopMovingIndex);
                    }
                    if (m_selectionLength > 0)
                    {
                        int endIndex = m_selectionStart + m_selectionLength - 1;
                        if (endIndex >= m_text.Length)
                        {
                            endIndex = m_text.Length - 1;
                        }
                        bool isAllNextLine = false;
                        for (int i = m_selectionStart; i <= endIndex; i++)
                        {
                            if (m_text[i] != '\r' && m_text[i] != '\n')
                            {
                                isAllNextLine = true;
                            }
                        }
                        if (!isAllNextLine)
                        {
                            m_selectionLength = 0;
                        }
                    }
                    invalidate();
                }
            }
        }

        /// <summary>
        /// 触摸抬起方法
        /// </summary>
        /// <param name="touchInfo">触摸信息</param>
        public override void onTouchUp(FCTouchInfo touchInfo)
        {
            m_isTouchDown = false;
            base.onTouchUp(touchInfo);
        }

        /// <summary>
        /// 重绘前景方法
        /// </summary>
        /// <param name="paint">绘图对象</param>
        /// <param name="clipRect">裁剪区域</param>
        public override void onPaintForeground(FCPaint paint, FCRect clipRect)
        {
            int width = getWidth(), height = getHeight();
            if (width > 0 && height > 0)
            {
                int lineHeight = m_multiline ? m_lineHeight : height;
                FCPadding padding = getPadding();
                FCHost host = getNative().getHost();
                FCRect rect = new FCRect(0, 0, width, height);
                FCFont font = getFont();
                FCSizeF tSize = paint.textSizeF(" ", font, -1);
                FCHScrollBar hScrollBar = getHScrollBar();
                FCVScrollBar vScrollBar = getVScrollBar();
                int vWidth = (vScrollBar != null && vScrollBar.isVisible()) ? vScrollBar.getWidth() : 0;
                int scrollH = ((hScrollBar != null && hScrollBar.isVisible()) ? hScrollBar.getPos() : 0);
                int scrollV = ((vScrollBar != null && vScrollBar.isVisible()) ? vScrollBar.getPos() : 0);
                float strX = padding.left + 1;
                //绘制文字
                String text = getText();
                if (text == null)
                {
                    text = "";
                }
                int length = text.Length;
                FCSizeF bSize = paint.textSizeF("0", font, -1);
                if (m_textChanged || m_changeID != FCNative.getChangeID())
                {
                    m_changeID = FCNative.getChangeID();
                    int line = 0, count = 0;
                    //获取绘制区域
                    m_textChanged = !m_textChanged;
                    m_lines.clear();
                    m_ranges.clear();
                    m_wordsSize.clear();
                    int realLine = 1;
                    for (int i = 0; i < length; i++)
                    {
                        if (i == 0)
                        {
                            count = 0;
                            line++;
                            strX = padding.left + 1;
                            FCWordLine wl = new FCWordLine(i, i);
                            wl.m_line = realLine;
                            m_lines.add(wl);
                        }
                        char ch = text[i];
                        bool isNextLine = false;
                        String dch = ch.ToString();
                        //制表符
                        if (ch == 9)
                        {
                            int addCount = 4 - count % 4;
                            tSize.cx = bSize.cx * addCount;
                            tSize.cy = bSize.cy;
                            count += addCount;
                        }
                        else
                        {
                            //密码替换
                            if (m_passwordChar != 0)
                            {
                                dch = m_passwordChar.ToString();
                            }
                            tSize = paint.textSizeF(dch, font, -1);
                            if (ch == 10 || ch == 13)
                            {
                                tSize.cx = bSize.cx;
                            }
                            count++;
                        }
                        //判断是否多行
                        if (m_multiline)
                        {
                            if (ch == 13)
                            {
                                //修改
                                if (i < length - 1 && text[i + 1] == 10)
                                {

                                }
                                else
                                {
                                    isNextLine = true;
                                    realLine++;
                                }
                                tSize.cx = 0;
                                count = 0;
                            }
                            else if (ch == 10)
                            {
                                isNextLine = true;
                                realLine++;
                                count = 0;
                                tSize.cx = 0;
                            }
                            else
                            {
                                //是否自动换行
                                if (m_wordWrap)
                                {
                                    if (strX + tSize.cx > width - vWidth - padding.right - tSize.cx)
                                    {
                                        if (i != length - 1 && (text[i + 1] == '\r' || text[i + 1] == '\n'))
                                        {

                                        }
                                        else
                                        {
                                            isNextLine = true;
                                        }
                                    }
                                }
                            }
                            FCWordLine wl = new FCWordLine(m_lines[line - 1].m_start, i);
                            wl.m_line = m_lines[line - 1].m_line;
                            m_lines[line - 1] = wl;
                        }
                        else
                        {
                            FCWordLine wl = new FCWordLine(m_lines[line - 1].m_start, i);
                            wl.m_line = m_lines[line - 1].m_line;
                            m_lines[line - 1] = wl;
                        }
                        if (ch > 1000)
                        {
                            tSize.cx += 1;
                        }
                        //保存区域
                        FCRectF rangeRect = new FCRectF(strX, padding.top + (line - 1) * lineHeight, strX + tSize.cx, padding.top + line * lineHeight);
                        m_ranges.add(rangeRect);
                        m_wordsSize.add(tSize);
                        strX = rangeRect.right;
                        if (isNextLine)
                        {
                            line++;
                            strX = padding.left + 1;
                            if (i != length - 1)
                            {
                                FCWordLine wl = new FCWordLine(i + 1, i + 1);
                                wl.m_line = realLine;
                                m_lines.add(wl);
                            }
                        }
                    }
                    //从右向左
                    if (m_rightToLeft)
                    {
                        int lcount = m_lines.size();
                        for (int i = 0; i < lcount; i++)
                        {
                            FCWordLine ln = m_lines[i];
                            float lw = width - vWidth - (m_ranges[ln.m_end].right - m_ranges[ln.m_start].left) - 2;
                            if (lw > 0)
                            {
                                for (int j = ln.m_start; j <= ln.m_end; j++)
                                {
                                    FCRectF rangeRect = m_ranges[j];
                                    rangeRect.left += lw;
                                    rangeRect.right += lw;
                                    m_ranges[j] = rangeRect;
                                }
                            }
                        }
                    }
                    update();
                }
                scrollH += m_offsetX;
                FCRect tempRect = new FCRect();
                int rangesSize = m_ranges.size();
                int offsetX = m_offsetX;
                //判断当前索引是否可见
                if (!m_multiline)
                {
                    FCRectF firstRange = new FCRectF();
                    FCRectF lastRange = new FCRectF();
                    if (rangesSize > 0)
                    {
                        firstRange = m_ranges[0];
                        lastRange = m_ranges[rangesSize - 1];
                    }
                    scrollH -= offsetX;
                    //居中
                    if (m_textAlign == FCHorizontalAlign.Center)
                    {
                        offsetX = -(int)(width - padding.right - (lastRange.right - firstRange.left)) / 2;
                    }
                    //远离
                    else if (m_textAlign == FCHorizontalAlign.Right)
                    {
                        offsetX = -(int)(width - padding.right - (lastRange.right - firstRange.left) - 3);
                    }
                    //居左
                    else
                    {
                        //显示超出边界
                        if (isFocused() && lastRange.right > width - padding.right)
                        {
                            //获取总是可见的索引
                            int alwaysVisibleIndex = m_selectionStart + m_selectionLength;
                            if (m_startMovingIndex != -1)
                            {
                                alwaysVisibleIndex = m_startMovingIndex;
                            }
                            if (m_stopMovingIndex != -1)
                            {
                                alwaysVisibleIndex = m_stopMovingIndex;
                            }
                            if (alwaysVisibleIndex > rangesSize - 1)
                            {
                                alwaysVisibleIndex = rangesSize - 1;
                            }
                            if (alwaysVisibleIndex != -1)
                            {
                                FCRectF alwaysVisibleRange = m_ranges[alwaysVisibleIndex];
                                int cw = width - padding.left - padding.right;
                                if (alwaysVisibleRange.left - offsetX > cw - 10)
                                {
                                    offsetX = (int)alwaysVisibleRange.right - cw + 3;
                                    if (offsetX < 0)
                                    {
                                        offsetX = 0;
                                    }
                                }
                                else if (alwaysVisibleRange.left - offsetX < 10)
                                {
                                    offsetX -= (int)bSize.cx * 4;
                                    if (offsetX < 0)
                                    {
                                        offsetX = 0;
                                    }
                                }
                                if (offsetX > lastRange.right - cw)
                                {
                                    offsetX = (int)lastRange.right - cw + 3;
                                }
                            }
                        }
                        //显示未超出边界
                        else
                        {
                            if (m_textAlign == FCHorizontalAlign.Right)
                            {
                                offsetX = -(int)(width - padding.right - (lastRange.right - firstRange.left) - 3);
                            }
                            else
                            {
                                offsetX = 0;
                            }
                        }
                    }
                    m_offsetX = offsetX;
                    scrollH += m_offsetX;
                }
                int lineCount = m_lines.size();
                //绘制矩形和字符
                ArrayList<FCRectF> selectedRanges = new ArrayList<FCRectF>();
                ArrayList<FCRectF> selectedWordsRanges = new ArrayList<FCRectF>();
                ArrayList<char> selectedWords = new ArrayList<char>();
                for (int i = 0; i < lineCount; i++)
                {
                    FCWordLine line = m_lines[i];
                    for (int j = line.m_start; j <= line.m_end; j++)
                    {
                        char ch = text[j];
                        if (ch != 9)
                        {
                            //密码替换
                            if (m_passwordChar > 0)
                            {
                                ch = m_passwordChar;
                            }
                        }
                        //获取绘制区域
                        FCRectF rangeRect = m_ranges[j];
                        rangeRect.left -= scrollH;
                        rangeRect.top -= scrollV;
                        rangeRect.right -= scrollH;
                        rangeRect.bottom -= scrollV;
                        FCRect rRect = new FCRect(rangeRect.left, rangeRect.top + (lineHeight - m_wordsSize[j].cy) / 2,
                            rangeRect.right, rangeRect.top + (lineHeight + m_wordsSize[j].cy) / 2);
                        float oldRangeTop = rangeRect.top;
                        rangeRect.top = oldRangeTop + (lineHeight - bSize.cy) / 2;
                        rangeRect.bottom = oldRangeTop + (lineHeight + bSize.cy) / 2;
                        if (rRect.right == rRect.left)
                        {
                            rRect.right = rRect.left + 1;
                        }
                        //绘制文字
                        if (host.getIntersectRect(ref tempRect, ref rRect, ref rect) > 0)
                        {
                            if (m_selectionLength > 0)
                            {
                                if (j >= m_selectionStart && j < m_selectionStart + m_selectionLength)
                                {
                                    selectedWordsRanges.add(rangeRect);
                                    selectedRanges.add(rangeRect);
                                    selectedWords.add(ch);
                                    continue;
                                }
                            }
                            paint.drawText(ch.ToString(), getPaintingTextColor(), font, rangeRect, -1);
                        }
                    }
                }
                //绘制选中区域
                int selectedRangesSize = selectedRanges.size();
                if (selectedRangesSize > 0)
                {
                    int sIndex = 0;
                    float right = 0;
                    for (int i = 0; i < selectedRangesSize; i++)
                    {
                        FCRectF rRect = selectedRanges[i];
                        FCRectF sRect = selectedRanges[sIndex];
                        bool newLine = rRect.top != sRect.top;
                        if (newLine || i == selectedRangesSize - 1)
                        {
                            int eIndex = (i == selectedRangesSize - 1) ? i : i - 1;
                            FCRectF eRect = selectedRanges[eIndex];
                            FCRect unionRect = new FCRect(sRect.left, sRect.top, eRect.right + 1, sRect.bottom + 1);
                            if (newLine)
                            {
                                unionRect.right = (int)right;
                            }
                            paint.fillRect(m_selectionBackColor, unionRect);
                            for (int j = sIndex; j <= eIndex; j++)
                            {
                                paint.drawText(selectedWords[j].ToString(), m_selectionTextColor, font, selectedWordsRanges[j], -1);
                            }
                            sIndex = i;
                        }
                        right = rRect.right;
                    }
                    selectedRanges.clear();
                    selectedWords.clear();
                    selectedWordsRanges.clear();
                }
                m_isCopy = false;
                //绘制光标
                if (isFocused() && !m_readOnly && m_selectionLength == 0 && (m_isKeyDown || m_showCursor))
                {
                    int index = m_selectionStart;
                    if (index < 0)
                    {
                        index = 0;
                    }
                    if (index > length)
                    {
                        index = length;
                    }
                    //获取光标的位置
                    int cursorX = offsetX;
                    if (m_textAlign == FCHorizontalAlign.Left && m_text.Length == 0)
                    {
                        cursorX = padding.left;
                    }
                    int cursorY = 0;
                    if (length > 0)
                    {
                        int showIndex = index - 1;
                        if (showIndex != -1)
                        {
                            bool nextLine = false;
                            if (m_multiline)
                            {
                                for (int i = 0; i < m_lines.size(); i++)
                                {
                                    FCWordLine wordLine = m_lines[i];
                                    if (showIndex == wordLine.m_end)
                                    {
                                        if (i != m_lines.size() - 1)
                                        {
                                            nextLine = true;
                                            cursorX = (int)Math.Floor(m_ranges[showIndex + 1].left);
                                            cursorY = (int)Math.Ceiling(m_ranges[showIndex + 1].top);
                                        }
                                        else
                                        {
                                            if (text[showIndex] == '\r' || text[showIndex] == '\n')
                                            {
                                                nextLine = true;
                                                cursorX = (int)Math.Floor(m_ranges[0].left);
                                                cursorY = (int)Math.Ceiling(m_ranges[showIndex].top + m_lineHeight);
                                            }
                                        }
                                        break;
                                    }
                                }
                            }
                            if (!nextLine)
                            {
                                cursorX = (int)Math.Floor(m_ranges[showIndex].right);
                                cursorY = (int)Math.Ceiling(m_ranges[showIndex].top);
                            }
                        }
                        else
                        {
                            cursorX = (int)Math.Floor(m_ranges[0].left);
                            cursorY = (int)Math.Ceiling(m_ranges[0].top);
                        }
                        cursorY += lineHeight / 2 - (int)tSize.cy / 2;
                    }
                    else
                    {
                        cursorY = padding.top + lineHeight / 2 - (int)tSize.cy / 2;
                    }
                    m_cursorPoint.x = cursorX - scrollH;
                    m_cursorPoint.y = cursorY - scrollV;
                    //绘制闪烁光标
                    if (m_isKeyDown || m_showCursor)
                    {
                        FCRect cRect = new FCRect(cursorX - scrollH, cursorY - scrollV, cursorX - scrollH + 2, cursorY + tSize.cy - scrollV);
                        paint.fillRect(getTextColor(), cRect);
                    }
                }
                else
                {
                    if (!isFocused() && text.Length == 0)
                    {
                        if (m_tempText != null && m_tempText.Length > 0)
                        {
                            FCSize pSize = paint.textSize(m_tempText, font, -1);
                            FCRect pRect = new FCRect();
                            pRect.left = padding.left;
                            pRect.top = (lineHeight - pSize.cy) / 2;
                            pRect.right = pRect.left + pSize.cx;
                            pRect.bottom = pRect.top + pSize.cy;
                            paint.drawText(m_tempText, m_tempTextColor, font, pRect, -1);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 粘贴方法
        /// </summary>
        public override void onPaste()
        {
            if (!m_readOnly)
            {
                FCHost host = getNative().getHost();
                String insert = host.paste();
                if (insert != null && insert.Length > 0)
                {
                    int oldLines = m_lines.size();
                    FCRedoUndoInfo newReoUndoInfo = new FCRedoUndoInfo(getText(), getSelectionStart(), getSelectionLength());
                    insertWord(insert);
                    onTextChanged();
                    if (m_textChanged)
                    {
                        m_undoStack.Push(newReoUndoInfo);
                    }
                    invalidate();
                    if (!isLineVisible(m_selectionStart, 1.0f))
                    {
                        int newLines = m_lines.size();
                        if (newLines != oldLines)
                        {
                            FCVScrollBar vScrollBar = getVScrollBar();
                            if (vScrollBar != null)
                            {
                                vScrollBar.setPos(vScrollBar.getPos() + m_lineHeight * (newLines - oldLines));
                                invalidate();
                            }
                        }
                    }
                    update();
                    base.onPaste();
                }
            }
        }

        /// <summary>
        /// 被使用TAB切换方法
        /// </summary>
        public override void onTabStop()
        {
            base.onTabStop();
            if (!m_multiline)
            {
                if (getText() != null)
                {
                    int textSize = getText().Length;
                    if (textSize > 0)
                    {
                        m_selectionStart = 0;
                        m_selectionLength = textSize;
                        onTimer(m_timerID);
                    }
                }
            }
        }

        /// <summary>
        /// 尺寸改变时触发
        /// </summary>
        public override void onSizeChanged()
        {
            base.onSizeChanged();
            if (m_wordWrap)
            {
                m_textChanged = true;
                invalidate();
            }
        }

        /// <summary>
        /// 文字改变方法
        /// </summary>
        public override void onTextChanged()
        {
            m_textChanged = true;
            base.onTextChanged();
        }

        /// <summary>
        /// 秒表回调方法
        /// </summary>
        /// <param name="timerID">秒表ID</param>
        public override void onTimer(int timerID)
        {
            base.onTimer(timerID);
            if (m_timerID == timerID)
            {
                if (isVisible() && isFocused() && !m_textChanged)
                {
                    //m_showCursor = !m_showCursor;
                    //invalidate();
                }
            }
        }

        /// <summary>
        /// 重复
        /// </summary>
        /// <returns>重复命令</returns>
        public void redo()
        {
            if (canRedo())
            {
                FCRedoUndoInfo newReoUndoInfo = new FCRedoUndoInfo(getText(), getSelectionStart(), getSelectionLength());
                m_undoStack.Push(newReoUndoInfo);
                FCRedoUndoInfo oldRedo = m_redoStack.Pop();
                setText(oldRedo.m_text);
                setSelectionStart(oldRedo.m_selectionStart);
                setSelectionLength(oldRedo.m_selectionLength);
            }
        }

        /// <summary>
        /// 全选
        /// </summary>
        public void selectAll()
        {
            m_selectionStart = 0;
            if (getText() != null)
            {
                m_selectionLength = getText().Length;
            }
            else
            {
                m_selectionLength = 0;
            }
        }

        /// <summary>
        /// 设置移动索引
        /// </summary>
        /// <param name="sIndex">开始索引</param>
        /// <param name="eIndex">结束索引</param>
        private void setMovingIndex(int sIndex, int eIndex)
        {
            int textSize = getText().Length;
            if (textSize > 0)
            {
                if (sIndex < 0)
                {
                    sIndex = 0;
                }
                if (sIndex > textSize)
                {
                    sIndex = textSize;
                }
                if (eIndex < 0)
                {
                    eIndex = 0;
                }
                if (eIndex > textSize)
                {
                    eIndex = textSize;
                }
                m_startMovingIndex = sIndex;
                m_stopMovingIndex = eIndex;
                m_selectionStart = Math.Min(m_startMovingIndex, m_stopMovingIndex);
                m_selectionLength = Math.Abs(m_startMovingIndex - m_stopMovingIndex);
            }
        }

        /// <summary>
        /// 设置属性
        /// </summary>
        /// <param name="name">属性名称</param>
        /// <param name="value">属性值</param>
        public override void setAttribute(String name, String value)
        {
            switch (name)
            {
                case "lineheight":
                    setLineHeight(FCTran.strToInt(value));
                    break;
                case "multiline":
                    setMultiline(FCTran.strToBool(value));
                    break;
                case "passwordchar":
                    setPasswordChar(Convert.ToChar(value));
                    break;
                case "readonly":
                    setReadOnly(FCTran.strToBool(value));
                    break;
                case "righttoleft":
                    setRightToLeft(FCTran.strToBool(value));
                    break;
                case "selectionbackcolor":
                    setSelectionBackColor(FCTran.strToColor(value));
                    break;
                case "selectiontextcolor":
                    setSelectionTextColor(FCTran.strToColor(value));
                    break;
                case "temptext":
                    setTempText(value);
                    break;
                case "temptextcolor":
                    setTempTextColor(FCTran.strToColor(value));
                    break;
                case "textalign":
                    setTextAlign(FCTran.strToHorizontalAlign(value));
                    break;
                case "wordwrap":
                    setWordWrap(FCTran.strToBool(value));
                    break;
                default:
                    base.setAttribute(name, value);
                    break;
            }
        }

        /// <summary>
        /// 撤销
        /// </summary>
        /// <returns>撤销命令</returns>
        public void undo()
        {
            if (canUndo())
            {
                if (getText() != null)
                {
                    FCRedoUndoInfo newReoUndoInfo = new FCRedoUndoInfo(getText(), getSelectionStart(), getSelectionLength());
                    m_redoStack.Push(newReoUndoInfo);
                }
                FCRedoUndoInfo oldUndo = m_undoStack.Pop();
                setText(oldUndo.m_text);
                setSelectionStart(oldUndo.m_selectionStart);
                setSelectionLength(oldUndo.m_selectionLength);
            }
        }

        /// <summary>
        /// 更新布局方法
        /// </summary>
        public override void update()
        {
            if (m_native != null && !m_native.m_lockUpdate)
            {
                FCVScrollBar vScrollBar = getVScrollBar();
                if (vScrollBar != null)
                {
                    vScrollBar.setLineSize(m_lineHeight);
                }
                base.update();
            }
        }
    }
}
